/*
 * Moseycode
 * Copyright (C) 2008  Tom Gibara
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package com.tomgibara.mosey.vision.nat1ve;

import java.nio.ByteBuffer;

import com.tomgibara.mosey.vision.Ellipse;
import com.tomgibara.mosey.vision.IntegerMath;
import com.tomgibara.mosey.vision.Processor;
import com.tomgibara.mosey.vision.RingIdentifier;

public class NativeProcessor extends Processor<ByteBuffer> {

	private ByteBuffer pixels;
	private final int[] ellipseData;
	private final boolean convertToBuffer;

	private byte[] yuvs;
	//used for testing/debug
	public int ellipseCount;
	
	private final int procWidth;
	private final int procHeight;
	
	public NativeProcessor(int width, int height, boolean convertToBuffer) {
		super(width, height);
		boolean okay = Native.init(width, height, 3);
		if (!okay) throw new RuntimeException("Failed to initialize native code.");
		procWidth = width;
		procHeight = height;
		this.convertToBuffer = convertToBuffer;
		ellipseData = new int[ellipses.length * Native.ELLIPSE_FIELDS];
	}
	
	public byte[] getYUVs() {
		return yuvs;
	}
	
	public void setYUVs(byte[] yuvs) {
		this.yuvs = yuvs;
	}
	
	@Override
	public ByteBuffer getPixels() {
		return pixels;
	}

	@Override
	public void setPixels(ByteBuffer pixels) {
		this.pixels = pixels;
	}
	
	@Override
	public int getProcessorWidth() {
		return procWidth;
	}

	@Override
	public int getProcessorHeight() {
		return procHeight;
	}

	@Override
	public boolean[] getThresh() {
		throw new UnsupportedOperationException();
	}

	@Override
	public int process() {
		if (pixels == null) throw new NullPointerException("No pixels set");
		final int[] data = ellipseData;
		final Ellipse[] es = ellipses;
		final int ellipseCount = Native.process(convertToBuffer, yuvs, procWidth, procHeight, pixels, ellipseData);
		this.ellipseCount = ellipseCount;
		//TODO move ring identification to native
		int j = 0;
		for (int i = 0; i < ellipseCount; i++) {
			Ellipse e = es[i];
			if (e == null) {
				e = new Ellipse();
				es[i] = e;
			}
			e.x     = data[j++];
			e.y     = data[j++];
			e.black = data[j++] == 1;
			// we do the sqrting in Java now, not in the native code 
//			e.minR  = data[j++];
//			e.maxR  = data[j++];
			e.minR  = IntegerMath.sqrt(data[j++]);
			e.maxR  = IntegerMath.sqrt(data[j++]);
			e.mx    = data[j++];
			e.my    = data[j++];
			e.nx    = data[j++];
			e.ny    = data[j++];
			e.sx    = data[j++];
			e.sy    = data[j++];
			e.sd    = data[j++];
			//System.out.println(e);
		}
		ringCount = RingIdentifier.identify(this, es, ellipseCount, rings);
		return ringCount;
	}

	@Override
	public void sampleValues(int[] points, int[] values) {
		int j = 0;
		for (int i = 0; i < values.length; i++) {
			int x = points[j++] * procWidth / viewWidth;
			int y = points[j++] * procHeight / viewHeight;
			if (x < 0) x = 0; else if (x >= procWidth) x = procWidth - 1;
			if (y < 0) y = 0; else if (y >= procHeight) y = procHeight - 1;
			values[i] = yuvs[y * procWidth + x] & 0xff;
		}
	}
	
	@Override
	public void sample(int[] points, boolean[] samples) {
		Native.sample(points, samples, viewWidth, viewHeight);
	}
	
	@Override
	public void sampleAverages(int[] points, int[] averages) {
		Native.sampleAverages(points, averages, viewWidth, viewHeight);
	}

	
}
